////////////////////////////////////////////////////////////////////////////////
//
// $Id$ 
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// 
// This software consists of voluntary contributions is licensed under the 
// MIT <http://www.opensource.org/licenses/mit-license.php>. 
// 
// 
// Portuguese Translation
// 
// ESTE SOFTWARE É FORNECIDO “COMO ESTÁ”, SEM GARANTIAS DE QUALQUER ESPÉCIE, 
// EXPRESSAS OU TÁCITAS, INCLUINDO SEM LIMITAÇÕES, QUAISQUER GARANTIA DE COMERCIABILIDADE, 
// DE ADEQUAÇÃO A FINALIDADES ESPECÍFICAS OU DE NÃO VIOLAÇÃO A DIREITOS DE TERCEIROS. 
// EM NENHUMA HIPÓTESE OS AUTORES OU TITULARES DOS DIREITOS AUTORAIS SERÃO RESPONSÁVEIS 
// POR QUAISQUER RECLAMAÇÕES E/OU INDENIZAÇÕES POR DANOS OU POR OUTROS MOTIVOS, 
// SEJAM ESSES DERIVADOS DE OBRIGAÇÕES CONTRATUAIS OU DE DECISÕES JUDICIAIS, 
// ILÍCITOS CIVIS OU OUTROS MOTIVOS, OS QUAIS VENHAM A OCORRER EM CONSEQÜÊNCIA 
// OU EM RELAÇÃO AO SOFTWARE , A SEU USO OU OUTRA FORMA DE NEGOCIAÇÃO/UTILIZAÇÃO. 
// 
// Esse software consiste de contribuições voluntárias e está sobre a licença
// MIT <http://www.opensource.org/licenses/mit-license.php>.
// 
////////////////////////////////////////////////////////////////////////////////

package br.mcaslib.swiz.view
{
	import br.mcaslib.common.Field;
	import br.mcaslib.common.FilterEngine;
	import br.mcaslib.common.Util;
	import br.mcaslib.swiz.controller.FeedbackController;
	import br.mcaslib.swiz.event.CrudEvent;
	import br.mcaslib.swiz.event.FeedbackEvent;
	
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	
	import mx.collections.ArrayCollection;
	import mx.collections.ArrayList;
	import mx.core.Container;
	import mx.core.IDeferredInstance;
	import mx.core.IVisualElement;
	import mx.core.UIComponent;
	import mx.events.FlexEvent;
	import mx.events.ValidationResultEvent;
	import mx.managers.PopUpManager;
	import mx.validators.Validator;
	
	import spark.components.Group;
	import spark.components.Panel;
	import spark.components.supportClasses.SkinnableComponent;
	import spark.layouts.supportClasses.LayoutBase;
	
	[SkinState("normal")]
	[SkinState("detail")]
	[SkinState("update")]
	[SkinState("add")]
	
	public class CrudContainer extends SkinnableComponent
	{
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------

		public function CrudContainer() {
			super();
			this.crudTokenId = Util.getUniqueID();
			this.crudContainer = new NullCrudLogic();
			this.addEventListener( FlexEvent.CREATION_COMPLETE, createComplete_Handler );
			this.addEventListener( FlexEvent.UPDATE_COMPLETE, updateComplete_Handler );
			trace( "CrudContainer: construct " + this );
		}
		
		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------

		[SkinPart(required="true")]
		public var toolbarSkinPart:Group;

		[SkinPart(required="true")]
		public var formSkinPart:Group;

		[SkinPart(required="true")]
		public var gridSkinPart:Group;
		
		[Bindable]
		public var titleGridPart:String;
		
		[Bindable]
		public var titleFormPart:String;
		
		[Bindable]
		public var gridPercentHeight:Number = 100;
		
		public var crudContainer:ICrudLogic;
				
		public var crudTokenId:String;
		
		public var filterEngine:FilterEngine;
		
		[ArrayElementType("FilterApply")]
		public var listFilterApply:Array;
		
		//----------------------------------
		//  toolbarMxmlContentFactory
		//----------------------------------
		
		private var _toolbarMxmlContentFactory:IDeferredInstance;
		
		[InstanceType("br.mcaslib.swiz.view.ICrudToolbar")]
		public function set toolbarMxmlContentFactory(value:IDeferredInstance):void {
			if (value == this._toolbarMxmlContentFactory)
				return;
			this._toolbarMxmlContentFactory = value;
		}
		
		private var toolbarMxmlContent:ICrudToolbar;

		//----------------------------------
		//  gridMxmlContentFactory
		//----------------------------------
		
		private var _gridMxmlContentFactory:IDeferredInstance;
		
		[InstanceType("mx.core.IVisualElement")]
		public function set gridMxmlContentFactory(value:IDeferredInstance):void {
			if (value == this._gridMxmlContentFactory)
				return;
			this._gridMxmlContentFactory = value;
		}
		
		private var gridMxmlContent:IVisualElement;
		
		//----------------------------------
		//  formMxmlContentFactory
		//----------------------------------
		
		private var _formMxmlContentFactory:IDeferredInstance;
		
		[InstanceType("mx.core.IVisualElement")]
		public function set formMxmlContentFactory(value:IDeferredInstance):void {
			if (value == this._formMxmlContentFactory)
				return;
			this._formMxmlContentFactory = value;
		}
		
		private var formMxmlContent:IVisualElement;

		//--------------------------------------------------------------------------
		//
		//  Handler methods
		//
		//--------------------------------------------------------------------------
		
		protected function toolbarSkinPart_handlerCrud( event:CrudEvent ):void {
			var item:Object;
			switch( event.action ) {
				case CrudEvent.ACTION_DETAIL:
					this.detailOn = ! this.detailOn;
					this.currentAction = "showitem";
					break;
				case CrudEvent.ACTION_CREATE:
					this.currentAction = "create";
					break;
				case CrudEvent.ACTION_UPDATE:
					item = this.crudContainer.getSelectedItem();
					if ( item ) {
						this.currentAction = "update";
					} else {
						FeedbackEvent.createEvent( 'Nenhum item selecionado' ).show(this)
					}
					break;
				case CrudEvent.ACTION_DELETE:
					if ( ! this.crudContainer.getSelectedItem() ) {
						this.currentAction = "delete";
					} else {
						FeedbackEvent.createEvent( 'Nenhum item selecionado' ).show(this)
					}
					break;
				case CrudEvent.ACTION_REFRESH:
					this.currentAction = "refresh";
					break;
				case CrudEvent.ACTION_FILTER:
					var filter: CrudFilterWindow = new CrudFilterWindow();
					filter.filterEngine = this.filterEngine;
					filter.setListFilterApply( this.listFilterApply );
					filter.addEventListener( CrudFilterWindow.EVENT_SUBMIT_OK, crudFilterWindow_submitOkHandler );
					filter.addEventListener( CrudFilterWindow.EVENT_SUBMIT_NOTAPPLY, crudFilterWindow_submitNotApplyHandler );
					PopUpManager.addPopUp( filter, this, true );
					PopUpManager.centerPopUp( filter );
					break;
			}
			this.invalidateAction = true;
			this.invalidateSkinState();
		}
		
		protected function createComplete_Handler( event:FlexEvent ):void {
			trace( 'CrudContainer - dispatch token id: ' + this.crudTokenId );
			var crudEvent:CrudEvent = new CrudEvent( CrudEvent.EVENT_CRUD_SET_TOKEN );
			crudEvent.crudTokenId = this.crudTokenId;
			this.dispatchEvent( crudEvent );
		}

		protected function updateComplete_Handler( event:FlexEvent ):void {
			trace( 'CrudContainer: Handler UPDATE_COMPLETE' );
			if( this.invalidateAction ) {
				trace( 'CrudContainer: Handler UPDATE_COMPLETE  Action:' + this.currentAction );
				this.invalidateAction = false;
				switch( this.currentAction ) {
					case 'create':
						this.crudContainer.prepareFormForAdd( this.crudContainer.getSelectedItem() );
						break;
					case 'update':
						this.crudContainer.prepareFormForUpdate( this.crudContainer.getSelectedItem() );
						break;
					case 'showitem':
						this.crudContainer.showForm( this.crudContainer.getSelectedItem() );
						break;
					case 'refresh':
						this.crudContainer.refresh();
						break;
				}
			}
		}
		
		protected function crudFilterWindow_submitOkHandler( event:Event ):void {
			var crudFilterWindow:CrudFilterWindow = event.currentTarget as CrudFilterWindow;
			this.listFilterApply = crudFilterWindow.getListFilterApply();
			var e:CrudEvent = new CrudEvent( CrudEvent.EVENT_CRUD_SERVER_LOAD, this.crudTokenId );
			e.filterApply = this.listFilterApply;
			this.dispatchEvent( e );
			
			if( this.listFilterApply && this.listFilterApply.length > 0 ) {
				this.toolbarMxmlContent.filterApplied(true);
			} else {
				this.toolbarMxmlContent.filterApplied(false);
			}
		}
		
		protected function crudFilterWindow_submitNotApplyHandler( event:Event ):void {
			var crudFilterWindow:CrudFilterWindow = event.currentTarget as CrudFilterWindow;
			this.listFilterApply = crudFilterWindow.getListFilterApply();
			var e:CrudEvent = new CrudEvent( CrudEvent.EVENT_CRUD_SERVER_LOAD, this.crudTokenId );
			e.filterApply = new Array();
			this.dispatchEvent( e );
			this.toolbarMxmlContent.filterApplied(false);
		}
		
		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------
		
		public function cancelAction():void {
			if( this.detailOn ) {
				this.cancelledAction = false;
				this.currentAction = "showitem";
				this.invalidateAction = true;
				
			} else {
				this.cancelledAction = true;
				
			}
			this.invalidateSkinState();
		}
		
		public function applyAction():void {
			if( ! this.crudContainer.isFieldsValidate() ) {
				FeedbackEvent.createEvent( "Existem erros no preenchimento de alguns campos.\nPosicione o mouse em cima dos campos com borda vermelha para ver a mensagem de erro" ).show(this);
				return;
			}
			
			var vo:Object = this.crudContainer.getObjectVO()
			var event:CrudEvent = new CrudEvent( CrudEvent.EVENT_CRUD_SERVER_SAVE );
			event.vo = vo;
			event.crudTokenId = this.crudTokenId;
			this.dispatchEvent( event );
		}

		public function changeItem():void {
			this.crudContainer.showForm( this.crudContainer.getSelectedItem() );
		}

		public function validateFields( validators:Array ):Boolean {
			var result: Boolean = true;
			for each (var validator:Validator in validators) {
				var validator_result:ValidationResultEvent;
				if( validator.enabled ) {
					validator_result = validator.validate();
					if( validator_result.type == ValidationResultEvent.INVALID ) {
						result = false;
					}
				}
			}
			return result;
		}
		
		public function resetValidateFields( validators:Array ):void {
			callLater( callLaterResetValidateFields, new Array(validators)  );
		}
			
		public function getCrudEventLoadFilterEngine():CrudEvent {
			var crudEvent:CrudEvent = new CrudEvent( CrudEvent.EVENT_CRUD_SERVER_LOAD_FILTER );
			crudEvent.crudTokenId = this.crudTokenId;
			return crudEvent;
		}
		
		public function loadFilterEngine():void {
			this.dispatchEvent( this.getCrudEventLoadFilterEngine() );
		}
		
		public function getCrudEventLoadCollection():CrudEvent {
			var event:CrudEvent = new CrudEvent( CrudEvent.EVENT_CRUD_SERVER_LOAD, this.crudTokenId );
			return event;
		}
		
		public function loadCollection():void {
			this.dispatchEvent( this.getCrudEventLoadCollection() );
		}
		
		//--------------------------------------------------------------------------
		//
		//  Handler Methods
		//
		//--------------------------------------------------------------------------

		[EventHandler(event='CrudEvent.EVENT_CRUD_SERVER_SAVE_COMPLETE', properties='crudTokenId,itemSaved')]
		public function saveCompleteHandler( crudTokenId:String, itemSaved:Object ):void {
			if( crudTokenId == this.crudTokenId ) {
				this.cancelAction();
				this.crudContainer.setSelectedItem( itemSaved );
			}
		}
		
		[EventHandler(event='CrudEvent.EVENT_CRUD_SERVER_LOAD_FILTER_COMPLETE', properties='crudTokenId,filterEngine')]
		public function loadFilterCompleteHandler( crudTokenId:String, filterEngine:FilterEngine ):void {
			if( crudTokenId == this.crudTokenId ) {
				if( filterEngine ) {
					if( this.toolbarMxmlContent ) {
						this.toolbarMxmlContent.turnFilter(true);
						this.toolbarMxmlContent.turnQuickFilter(true);
						this.filterEngine = filterEngine;
					}
				} else {
					if( this.toolbarMxmlContent ) {
						this.toolbarMxmlContent.turnFilter(false);
						this.toolbarMxmlContent.turnQuickFilter(false);
						this.filterEngine = null;
					}
				}
			}
		}
		
		
		
		//--------------------------------------------------------------------------
		//
		//  Overridden methods
		//
		//--------------------------------------------------------------------------
		
		/**
		 *  @inheritDoc
		 */
		override protected function partAdded(partName:String, instance:Object):void {
			var content:Array
			
			super.partAdded(partName, instance);
			
			this.createMxmlContent();
			
			if (instance == toolbarSkinPart) {
				this.toolbarMxmlContent.addEventListener( CrudEvent.EVENT_CRUD_ACTION, toolbarSkinPart_handlerCrud );
				content = new Array();
				content.push( this.toolbarMxmlContent );
				toolbarSkinPart.mxmlContent = content;
			}
			
			if (instance == gridSkinPart) {
				content = new Array();
				content.push( this.gridMxmlContent );
				gridSkinPart.mxmlContent = content;
			}
			
			if (instance == formSkinPart) {
				content = new Array();
				content.push( this.formMxmlContent );
				formSkinPart.mxmlContent = content;
			}
		}
		
		/**
		 *  @inheritDoc
		 */
		override protected function partRemoved(partName:String, instance:Object):void {
			super.partRemoved(partName, instance);

			if (instance == toolbarSkinPart) {
				this.toolbarSkinPart.mxmlContent = null;
			}
			
			if (instance == gridSkinPart) {
				this.gridSkinPart.mxmlContent = null;
			}
			
			if (instance == formSkinPart) {
				this.formSkinPart.mxmlContent = null;
			}
		}
		
		/**
		 * @todo Fazer o unittest desse metodo
		 */
		override protected function getCurrentSkinState():String {
			var state:String = "normal";
			
			if( this.detailOn ) {
				state = 'detail';
			}
			
			if( this.cancelledAction ) {
				this.cancelledAction = false;
				this.currentAction = null;
			}
			
			if( this.currentAction == "create" ) {
				state = "add";
			}
			
			if( this.currentAction == "update" ) {
				state = "update";
			}
			
			if( this.toolbarMxmlContent ) {
				this.toolbarMxmlContent.setCrudState( state );
			}
			
			/*
			if( this.gridMxmlContent ) {
				this.gridMxmlContent.setCrudState( state );
			}
			
			if( this.formMxmlContent ) {
				this.formMxmlContent.setCrudState( state );
			}
			*/
			
			this.crudContainer.setCrudState( state );
			
			return state; 
		}

		//--------------------------------------------------------------------------
		//
		//  Private / Protected properties
		//
		//--------------------------------------------------------------------------

		protected var detailOn:Boolean = false;
		
		protected var currentAction:String = "normal";
		
		protected var invalidateAction:Boolean = false;
		
		protected var cancelledAction:Boolean = false;
		
		//--------------------------------------------------------------------------
		//
		//  Private / Protected methods
		//
		//--------------------------------------------------------------------------
		
		protected function createMxmlContent():void {
			var deferredContent:Object;
			
			if( ! this.toolbarMxmlContent && this._toolbarMxmlContentFactory ) {
				deferredContent = this._toolbarMxmlContentFactory.getInstance();
				this.toolbarMxmlContent = deferredContent as ICrudToolbar;
			}
			
			if( ! this.gridMxmlContent && this._gridMxmlContentFactory ) {
				deferredContent = this._gridMxmlContentFactory.getInstance();
				this.gridMxmlContent = deferredContent as IVisualElement;
			}
			
			if( ! this.formMxmlContent && this._formMxmlContentFactory ) {
				deferredContent = this._formMxmlContentFactory.getInstance();
				this.formMxmlContent = deferredContent as IVisualElement;
			}
		}
		
		public function callLaterResetValidateFields( validators:Array ):void {
			for each (var validator:Validator in validators) {
				if( validator.source != null ) {
					UIComponent(validator.source).errorString = "";
				}
			}
		}

	}
}
